package dimension.stock;

import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.util.concurrent.locks.ReentrantLock;

public class Exchanger {

    private static final ReentrantLock LOCK = new ReentrantLock();

    public static BigDecimal getLatestPrice() {
        return Config.getLatestPrice();
    }

    public static BigDecimal getLastDayPrice() {
        return Config.getLastDayPrice();
    }

    public static void buy(CommandSender sender,long count) {
        LOCK.lock();
        try {
            if (count%100!=0) {
                sender.sendMessage(MainClass.PREFIX + " §7购买§c§n失败§7，股数必须是100的倍数");
                return;
            }
            BigDecimal latestPrice = Config.getLatestPrice();

            BigDecimal playerMoney = BigDecimal.valueOf(MainClass.ECONOMY.getBalance((Player)sender));
            long totalStock = Config.getAvailableStock(sender.getName());

            BigDecimal a1 = Config.getTradeRate().multiply(new BigDecimal(count)).multiply(new BigDecimal(count));
            BigDecimal a2 = latestPrice.subtract(Config.getTradeRate()).multiply(new BigDecimal(count));
            BigDecimal totalMoney = a1.add(a2);

            latestPrice = new BigDecimal(2).multiply(totalMoney).divide(new BigDecimal(count),100, RoundingMode.HALF_UP).subtract(latestPrice).setScale(100,RoundingMode.HALF_UP);
            BigDecimal avgPrice = totalMoney.divide(new BigDecimal(count),2,RoundingMode.HALF_UP);

            BigDecimal rate = latestPrice.subtract(Config.getLastDayPrice()).multiply(new BigDecimal(100)).divide(Config.getLastDayPrice(), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);

            if (rate.compareTo(Config.getLimit().multiply(new BigDecimal(100))) > 0) {
                sender.sendMessage(MainClass.PREFIX + " §7购买§c§n失败§7，涨停限制");
                return;
            }
            if (playerMoney.compareTo(totalMoney) < 0) {
                sender.sendMessage(MainClass.PREFIX + " §7购买§c§n失败§7，余额不足");
                return;
            }
            Config.saveLatestPrice(latestPrice);
            Config.saveAvailableStock(sender.getName(),totalStock + count);
            MainClass.ECONOMY.withdrawPlayer((Player) sender,totalMoney.doubleValue());
            sender.sendMessage(MainClass.PREFIX + " §7购买成功，金额§a " + totalMoney.setScale(2,RoundingMode.HALF_UP) + " §7均价 §a" + avgPrice + "§7 数量 §a" + count + "§7 当前持仓 §a" + (totalStock + count));
            broadcast(latestPrice,count < 5000,rate);
            Config.setTodayVolume(Config.getTodayVolume().add(new BigInteger(String.valueOf(count))));
        } finally {
            LOCK.unlock();
        }
    }

    private static long lastBroadcastTime = 0;
    private static void broadcast(BigDecimal latestPrice, boolean hasLimit,BigDecimal rate) {
        if (hasLimit && System.currentTimeMillis() - lastBroadcastTime < 60*1000) {
            return;
        }
        lastBroadcastTime = System.currentTimeMillis();

        Bukkit.getOnlinePlayers().forEach(player -> {
            boolean isDown = rate.compareTo(BigDecimal.ZERO) < 0;
            BigDecimal price = latestPrice.setScale(2,RoundingMode.HALF_UP);
            player.sendMessage(MainClass.PREFIX + " §7股票 §f" + Config.getStockName() + " §7最新成交价为 §a" + price + " §7涨跌幅 §" + (isDown?"a":"c") + rate + "%");
        });
    }

    public static void sell(CommandSender sender,long count) {
        LOCK.lock();
        try {
            if (count%100!=0) {
                sender.sendMessage(MainClass.PREFIX + " §7出售§c§n失败§7，股数必须是100的倍数");
                return;
            }
            BigDecimal latestPrice = Config.getLatestPrice();
            long stockCount = Config.getAvailableStock(sender.getName());
            if (stockCount < count) {
                sender.sendMessage(MainClass.PREFIX + " §7出售§c§n失败§7，没有足够的股票，当前持股 §f" + Config.getStockName() + "§7 数为 §a" + stockCount);
                return;
            }
            BigDecimal a1 = Config.getTradeRate().negate().multiply(new BigDecimal(count)).multiply(new BigDecimal(count));
            BigDecimal a2 = latestPrice.subtract(Config.getTradeRate().negate()).multiply(new BigDecimal(count));
            BigDecimal totalMoney = a1.add(a2);

            latestPrice = new BigDecimal(2).multiply(totalMoney).divide(new BigDecimal(count),100, RoundingMode.HALF_UP).subtract(latestPrice).setScale(100,RoundingMode.HALF_UP);
            BigDecimal avgPrice = totalMoney.divide(new BigDecimal(count),2,RoundingMode.HALF_UP);

            BigDecimal rate = latestPrice.subtract(Config.getLastDayPrice()).multiply(new BigDecimal(100)).divide(Config.getLastDayPrice(), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);

            if (rate.compareTo(Config.getLimit().multiply(new BigDecimal(100)).negate()) < 0) {
                sender.sendMessage(MainClass.PREFIX + " §7出售§c§n失败§7，跌停限制");
                return;
            }
            if (latestPrice.compareTo(BigDecimal.ZERO) < 0) {
                sender.sendMessage(MainClass.PREFIX + " §7出售§c§n失败§7，跌停限制");
                return;
            }

            Config.saveLatestPrice(latestPrice);
            Config.saveAvailableStock(sender.getName(),stockCount - count);
            MainClass.ECONOMY.depositPlayer((Player) sender,totalMoney.doubleValue());
            sender.sendMessage(MainClass.PREFIX + " §7出售成功，金额§a " + totalMoney.setScale(2,RoundingMode.HALF_UP) + " §7均价 §a" + avgPrice + "§7 数量 §a" + count + " §7当前持仓 §a" + (stockCount - count));
            broadcast(latestPrice,count < 5000,rate);
            Config.setTodayVolume(Config.getTodayVolume().add(new BigInteger(String.valueOf(count))));
        } finally {
            LOCK.unlock();
        }
    }

    public static void autoBuySell() {
        SecureRandom secureRandom = new SecureRandom();
        LOCK.lock();
        try {
            BigDecimal latestPrice = Config.getLatestPrice();
            if (secureRandom.nextInt(100) > 50) {
                latestPrice = latestPrice.multiply(BigDecimal.ONE.add(new BigDecimal(secureRandom.nextInt(2) + 1).divide(new BigDecimal(100),100,RoundingMode.HALF_UP))).setScale(100,RoundingMode.HALF_UP);
            } else {
                latestPrice = latestPrice.multiply(BigDecimal.ONE.subtract(new BigDecimal(secureRandom.nextInt(2) + 1).divide(new BigDecimal(100),100,RoundingMode.HALF_UP))).setScale(100,RoundingMode.HALF_UP);
            }
            BigDecimal rate = latestPrice.subtract(Config.getLastDayPrice()).multiply(new BigDecimal(100)).divide(Config.getLastDayPrice(), RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP);
            if (rate.compareTo(Config.getLimit().multiply(new BigDecimal(100))) > 0 || rate.compareTo(Config.getLimit().multiply(new BigDecimal(100)).negate()) < 0) {
                return;
            }
            Config.saveLatestPrice(latestPrice);
            broadcast(latestPrice,false,rate);
        } finally {
            LOCK.unlock();
        }
    }

}
